<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 10px;
            overflow: hidden;
        }

        body {
            background: #333;
        }

        #canvas {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            border: 1px solid white;
            /* cursor:none; */
            filter: drop-shadow(0 0 2px white);
        }

        #start {
            width: 120px;
            height: 40px;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            font-size: 28px;
            padding: 5px;
            border-radius: 4px;
            display: flex;
            background: rgba(255, 255, 255, 0.4);
            justify-content: center;
        }
    </style>

</head>

<body>
    <canvas id="canvas"></canvas>
    <button id="start" onclick="start()">START</button>
    <script>
        class blockclass {
            constructor(_x, _y, _color) {
                this.x = _x;
                this.y = _y;
                this.color = _color;
            }
        }
        class board {
            constructor(_x, _y, _long = 100) {
                this.x = _x;
                this.y = _y;
                this.long = _long;

            }
        }
        class ball {
            vx = null; vy = null;
            constructor(_sx, _sy, _color = "white") {
                this.sx = _sx;
                this.sy = _sy;
                this.color = _color;
            }
        }
        class canvasanimotion {
            canvas = null;
            ctx = null;
            board = null;//移动板
            blocks = [] //砖块数组
            colors = [ //颜色数组
                "#eccc68",
                "#ff7f50",
                "#ff6b81",
                "#7bed9f",
                "#5352ed",
                "#70a1ff"
            ]
            speed = 0.3 //弹球移动速度
            run = null
            fires = [] //烟火数组
            score = 0 //分数
            rungame = false //默认运行状态
            interval = null
            constructor() {
                this.canvas = document.getElementById("canvas")
                this.ctx = canvas.getContext("2d")
                this.canvas.width = window.innerWidth || document.documentElement.clientWidth;
                this.canvas.height = window.innerHeight || document.documentElement.clientHeight;
                this.run = document.getElementById("start")
                this.board = new board(350, this.canvas.height - 20)
            }
            newgame() {

                this.ball = new ball(this.canvas.width / 2, this.canvas.height / 2)
                this.ball.vx = (0.5 - Math.random()) * this.speed
                this.ball.vy = Math.sqrt(this.speed * this.speed - this.ball.vx * this.ball.vx)
                this.score = 0
                this.blocks = []
                for (var i = 0; i < Math.floor(this.canvas.width / 80); i++) { //生成砖块
                    for (var j = 0; j < Math.floor(this.canvas.height / 2 / 30); j++) {
                        this.blocks.push(new blockclass(i, j, this.colors[parseInt(Math.random() * this.colors.length)]))
                    }
                }
                this.cRect = this.canvas.getBoundingClientRect()
                let that = this
                window.addEventListener("mousemove", function (evt) { //移动鼠标变更反弹板位置
                    var x = evt.clientX - that.cRect.left
                    if (x < 50) {
                        that.board.x = 0
                    } else if (x > that.canvas.width) {
                        that.board.x = that.canvas.width - 50
                    } else {
                        that.board.x = x - 50
                    }
                })
            }
            draw() {
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)


                for (var i = 0; i < this.blocks.length; i++) { //绘制砖块
                    let block = this.blocks[i]
                    this.ctx.fillStyle = block.color
                    this.ctx.fillRect(block.x * 80 + 1, block.y * 30 + 1, 79, 29)
                    if (this.ball.sx + 10 > block.x * 80 + 1 && this.ball.sx - 10 < block.x * 80 + 80 && this.ball.sy + 10 > block.y * 30 + 1 && this.ball.sy - 10 < block.y * 30 + 30) { //砖块碰撞判断

                        if (this.ball.sx > block.x * 80 + 80 || this.ball.sx < block.x * 80) { //左右方向碰撞则改变x轴运行方向
                            this.ball.vx = -this.ball.vx
                        } else if (this.ball.sy > block.y * 30 + 30 || this.ball.sy < block.y * 30) { //垂直方向碰撞则改变Y轴运行方向
                            this.ball.vy = -this.ball.vy
                        }
                        if (this.ball.color == block.color) { //同色碰撞则加10分
                            this.score += 10
                        } else { //非同色碰撞加1分
                            this.score++
                        }
                        this.ball.color = block.color //撞击后球的颜色变成砖块颜色
                        this.blocks.splice(i, 1) //碰撞后砖块消失
                        for (var f = 0; f < 50; f++) { //生成火花
                            this.fires.push({
                                sx: block.x * 80 + 40,
                                sy: block.y * 30 + 15,
                                color: block.color,
                                vx: 0.5 - Math.random(),
                                vy: 0.5 - Math.random(),
                                age: 100
                            })
                        }
                    }
                }
                this.ctx.fillStyle = "white" //绘制分数
                this.ctx.font = "20px sans-serif"
                this.ctx.fillText(this.score, 5, 25)
                this.ctx.fillRect(this.board.x, this.board.y, this.board.long, 20) //绘制反弹板
                this.ctx.beginPath() //绘制小球
                this.ctx.fillStyle = this.ball.color
                this.ctx.arc(this.ball.sx, this.ball.sy, 10, 0, 2 * Math.PI)
                this.ctx.fill()

                if (this.rungame) { //判断游戏运行状态，并刷新球的位置
                    this.ball.sx += this.ball.vx * 5
                    this.ball.sy += this.ball.vy * 5
                    if (this.ball.sy < 10) { //上边缘碰撞判断
                        this.ball.vy = -this.ball.vy
                    }
                    if (this.ball.sx < 10 || this.ball.sx > 795) { //左右碰撞判断
                        this.ball.vx = -this.ball.vx
                    }
                    if (this.ball.sy > this.board.y && this.ball.sx > this.board.x && this.ball.sx < this.board.x + this.board.long) { //反弹板碰撞判断
                        this.ball.vx = (this.ball.sx - (this.board.x + this.board.long / 2)) / this.board.long / 2 * this.speed * 3
                        this.ball.vy = -Math.sqrt(this.speed * this.speed - this.ball.vx * this.ball.vx)
                        this.speed = this.speed * 1.001
                        for (var f = 0; f < 20; f++) {
                            this.fires.push({
                                sx: this.ball.sx,
                                sy: this.ball.sy + 10,
                                color: this.colors[parseInt(Math.random() * this.colors.length)],
                                vx: 0.5 - Math.random(),
                                vy: Math.random() - 1,
                                age: 60
                            })
                        }

                    }
                    if (this.ball.sy > (this.board.y + 20) || this.blocks.length <= 0) { //碰撞到底部或所有砖块都消失则游戏停止运行
                        this.rungame = false
                        this.run.style.display = "flex"
                        this.canvas.style.cursor = "default"
                        for (var f = 0; f < 150; f++) {
                            this.fires.push({
                                sx: 400,
                                sy: 300,
                                color: this.colors[parseInt(Math.random() * this.colors.length)],
                                vx: 0.5 - Math.random(),
                                vy: 0.5 - Math.random(),
                                age: 560
                            })
                        }
                    }
                }
                for (var i = 0; i < this.fires.length; i++) {
                    let fire = this.fires[i]
                    this.ctx.fillStyle = fire.color
                    this.ctx.fillRect(fire.sx, fire.sy, 2, 2)
                    fire.age--
                    if (fire.age < 0) {
                        this.fires.splice(i, 1)
                    }
                    fire.sx += fire.vx * 2
                    fire.sy += fire.vy * 2
                }
                if (!this.rungame)
                    clearInterval(this.interval)
            }
            start() {
                this.newgame()
                this.rungame = true
                this.run.style.display = "none"
                this.canvas.style.cursor = "none"
                this.interval = setInterval(() => {
                    this.draw()
                }, 1);
            }
        }

        let start = () => {
            let game = new canvasanimotion()
            game.start()
        }

    </script>

</body>

</html>